﻿using System;
using System.Collections.Generic;
using System.Text;
using Seasar.Framework.Aop;
using Seasar.Framework.Aop.Interceptors;
using System.Windows.Forms;
using System.Reflection;
using Seasar.Quill;
using Mayfair.Core.Common.FormManager.FormAttr;

namespace Mayfair.Core.Common.FormManager
{
    // diconファイルを書かずに属性を利用しています
    // その利点として、diconファイルへのリソースの設定を意識しなくても良くなります
    // かつ、遅延初期化で起動を速く出来ます

    /// <summary>
    /// フォーム生成・表示インターセプター
    /// FormInterceptor
    /// </summary>
    public class FormInterceptor : AbstractInterceptor
    {
        
        /// <summary>
        /// 返却値用プロパティ名
        /// Property for Returning
        /// </summary>
        private string _returnPropertyName = string.Empty;

        /// <summary>
        /// 返却値用プロパティ名
        /// Property for Returning
        /// </summary>
        public string Property
        {
            get { return _returnPropertyName; }
            set { _returnPropertyName = value; }
        }

        /// <summary>
        /// 指定フォーム表示
        /// Show the form you specify
        /// </summary>
        /// <param name="invocation"></param>
        /// <returns>DialogResult</returns>
        /// <remarks>
        /// 1.　　Defaultの返却値はDialogResult.No
        /// 2.　　modal/modelessフォームを表示
        /// 3.　　CreateFormAttributeに
        /// 3-1.　InitialMethodNameが設定されていれば、表示前にメソッドを実行出来ます
        /// 3-2.　返却値/引数が指定されていれば、受け渡しを行いフォームを表示
        /// 1.　　Returns(default) are DialogResult.No
        /// 2.　　Show the modal/modeles form
        /// 3.　　If CreateFormAttribute is
        /// 3-1.　setup InitialMethodName, execute the method before show
        /// 3-2.　setup returns or arguments, shuffle its back and forth, show the form
        /// </remarks>
        public override object Invoke(IMethodInvocation invocation)
        {
           
            // 参考URL(http://www.atmarkit.co.jp/fdotnet/dotnettips/359callbyname/callbyname.html,
            //         http://s2container.net.seasar.org/ja/aop-examples.html)

            DialogResult retOfReplace = DialogResult.No;

            object ret = retOfReplace;

            // メソッドの引数値の取得
            // Get Arguments
            object[] args = invocation.Arguments;
            ParameterInfo[] pis = invocation.Method.GetParameters();

            IDictionary<string, object> hashOfParams = new Dictionary<string, object>();
            IList<string> listOfParams = new List<string>();
            IDictionary<string, string> hashOfPropNames = new Dictionary<string, string>();

            foreach (ParameterInfo pi in pis)
            {
                hashOfParams.Add(pi.Name.ToLower(), args[pi.Position]);
                listOfParams.Add(pi.Name.ToLower());
            }

            // 全ての属性を含む配列を返す
            // Get the all custom ttributes 
            object[] attributes = invocation.Method.GetCustomAttributes(false);

            foreach (object o in attributes)
            {
                if (o is FormAttribute)
                {
                    // 返却値プロパティ名を取得
                    // Get ReturnPropertyName
                    FormAttribute attribute = (FormAttribute)o;
                    Type formType = attribute.FormType;

                    Form form = FormContainer.GetForm(formType);
                    QuillInjector injector = QuillInjector.GetInstance();

                    // *
                    // ver.1.4.0から削除予定
                    // ここら辺のQuilInjectorのインスタンスを取得するロジックを変える必要有り？
                    injector.ClearInjected();
                    // *

                    injector.Inject(form);
                    // 返却値プロパティ名の取得
                    // Get ReturnPropertyName
                    string propertyName = String.Empty;
                    if (attribute.ReturnPropertyName != String.Empty)
                        propertyName = attribute.ReturnPropertyName;

                    // フォームに値をセット
                    // setup it to the form
                    PropertyInfo[] infos = form.GetType().GetProperties();
                    foreach (PropertyInfo info in infos)
                    {
                        hashOfPropNames.Add(info.Name.ToLower(), info.Name);
                    }

                    for (int i = 0; i < listOfParams.Count; i++)
                    {
                        if (hashOfPropNames.ContainsKey(listOfParams[i]))
                        {
                            string propName = hashOfPropNames[listOfParams[i]];
                            PropertyInfo property = form.GetType().GetProperty(propName);
                            property.SetValue(form, hashOfParams[listOfParams[i]], null);
                       }
                    }
                    // 初期処理メソッド指定が有る場合
                    // If you specify InitialMethodName,
                    if (!string.IsNullOrEmpty(attribute.InitialMethodName))
                    {
                        CallMethod(form, attribute.InitialMethodName);
                    }

                    // WindowsForm表示
                    // Show the form
                    if (attribute.Mode == FormModalType.Modal)
                    {
                        retOfReplace = form.ShowDialog();
                        ret = retOfReplace;
                        // WindowsFormから返却値用プロパティから値を取得する
                        // Get the property to the form
                        if (propertyName != String.Empty)
                        {
                            PropertyInfo propInfo = form.GetType().GetProperty(propertyName);
                            if (propInfo != null)
                                ret = propInfo.GetValue(form, null);
                        }
                    }
                    else
                    {
                        form.Show();
                    }
                }
            }
            // 戻り値(DialogResult/Property)
            return ret;
        }

        /// <summary>
        /// Publicメソッド実行
        /// Execute Public Method
        /// </summary>
        /// <param name="form">対象フォーム(Target)</param>
        /// <param name="methodName">Publicメソッド名(MethodName)</param>
        private void CallMethod(Form form, string methodName)
        {
            MethodInfo mi;
            Type mc = form.GetType();
            try
            {
                mi = mc.GetMethod(methodName);
                if (mi != null)
                {
                    mi.Invoke(form, null);
                }
            }
            catch { }
        }

        // 不正遷移チェック(予定)

        // 遷移元により初期処理及び動作を変える(予定)

    }
}
